﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Drawing;

using LowLevelGraphics;

namespace LowLevelGraphics.Drawing.FloodFillModes
{
    public delegate bool FloodFillModeCheckCheck(Color _color1, Color _color2);

    /// <summary>
    /// Flood Fill Mode
    /// </summary>
    public class FloodFillMode : AbstractFloodFill
    {
        protected byte m_nR = 20;
        protected byte m_nG = 20;
        protected byte m_nB = 20;

        /// <summary>
        /// Initializes a new instance of the <see cref="FloodFillMode"/> class.
        /// </summary>
        public FloodFillMode()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FloodFillMode"/> class.
        /// </summary>
        /// <param name="_nR">The _n R.</param>
        /// <param name="_nG">The _n G.</param>
        /// <param name="_nB">The _n B.</param>
        public FloodFillMode(byte _nR, byte _nG, byte _nB)
        {
            m_nR = _nR;
            m_nG = _nG;
            m_nB = _nB;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="FloodFillMode"/> class.
        /// </summary>
        /// <param name="_floodFillMode">The _flood fill mode.</param>
        internal FloodFillMode(FloodFillMode _floodFillMode)
        {
            this.m_nR = _floodFillMode.m_nR;
            this.m_nG = _floodFillMode.m_nG;
            this.m_nB = _floodFillMode.m_nB;
        }

        /// <summary>
        /// Fills the specified bitmap.
        /// </summary>
        /// <param name="bitmap">The bitmap.</param>
        /// <param name="_ptX">The _PT X.</param>
        /// <param name="_ptY">The _PT Y.</param>
        /// <param name="_color">The _color.</param>
        public override void Fill(UnsafeBitmap bitmap, int _ptX, int _ptY, Color _color)
        {
            FloodFillModeCheckCheck floodFillCheck = new FloodFillModeCheckCheck(this.Check);
            
            int nMinY = _ptY;
            int nMaxY = _ptY;

            Color color = Color.Transparent;
            int y = 0;
            int x = 0;
            int nHeight = bitmap.Height;
            int nWidth = bitmap.Width;

            //Get the color
            Color colorStartPixel = bitmap.GetPixel(_ptX, _ptY);

            //Get topmost pixels
            for (y = _ptY - 1; y >= 0; y--)
            {
                color = bitmap.GetPixel(_ptX, y);
                if (!Check(color, colorStartPixel))
                {
                    nMinY = y;
                    break;
                }
                bitmap.SetPixelDirect(_ptX, y, _color);
            }

            //get bottom most pixels
            for (y = _ptY + 1; y < nHeight; y++)
            {
                color = bitmap.GetPixel(_ptX, y);
                if (!Check(color, colorStartPixel))
                {
                    nMaxY = y;
                    break;
                }
                bitmap.SetPixelDirect(_ptX, y, _color);
            }
            if (nMaxY == -1)
            {
                nMaxY = nHeight - 1;
            }

            //Since we got the borders now, let's walk from left to right
            //and right to left for each line
            int nCount = 0;

            int[,] aColor = new int[nWidth, nHeight];

            for (y = nMinY; y < nMaxY; y++)
            {
                for (x = _ptX - 1; x >= 0; x--)
                {
                    color = bitmap.GetPixel(x, y);
                    if (!floodFillCheck(color, colorStartPixel))
                    {
                        break;
                    }
                    aColor[x, y] = 1;
                    bitmap.SetPixelDirect(x, y, _color);
                    nCount++;
                }
                for (x = _ptX + 1; x < nWidth; x++)
                {
                    color = bitmap.GetPixel(x, y);
                    if (!floodFillCheck(color, colorStartPixel))
                    {
                        break;
                    }
                    aColor[x, y] = 1;
                    bitmap.SetPixelDirect(x, y, _color);
                    nCount++;
                }
            }
        }

        /// <summary>
        /// Checks the specified _color.
        /// </summary>
        /// <param name="_color">The _color.</param>
        /// <param name="_colorToCheck">The _color to check.</param>
        /// <returns></returns>
        public bool Check(Color _color, Color _colorToCheck)
        {
            return ColorFunctions.IsInColorTolerance(_color, _colorToCheck, m_nR, m_nG, m_nB);
        }

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public override object Clone()
        {
            return new FloodFillMode(this);
        }
    }
}
